package main

import (
	"funcdrawer"
	"funcparser"
	"image"
	"log"
	"net/http"
	"strconv"
	"text/template"
)

var (
	templates = template.Must(template.ParseFiles(
		"html/error.html",
		"html/home.html",
	))
)

func main() {
	http.HandleFunc("/display.jpg", errorHandler(display))
	http.HandleFunc("/", errorHandler(serve))
	http.ListenAndServe(":8080", nil)
}

// Parses the given function and generates a plot that is then written
// to the passed ResponseWriter.
func display(w http.ResponseWriter, r *http.Request) {
	f, err := funcparser.Parse(r.FormValue("f"))
	check(err)
	// Helper function.
	v := func(name string) int {
		i, _ := strconv.Atoi(r.FormValue(name))
		return i
	}
	w.Header().Set("Content-Type", "image")
	funcdrawer.DrawFunction(
		w, f, v("dx"), v("dy"),
		image.Rect(v("minX"), v("minY"), v("maxX"), v("maxY")),
		v("jpeg") == 1)
}

// Main point serving for web resources other than the function plot.
func serve(w http.ResponseWriter, r *http.Request) {
	path := r.URL.String()
	if path == "/" {
		// Add specs? The template name doesn't contain the folder ...
		check(templates.ExecuteTemplate(w, "home.html", nil))
	} else {
		other(w, r)
	}
}

// Serves any other resources such as css or images.
func other(w http.ResponseWriter, r *http.Request) {
	path := "./html" + r.URL.String()
	http.ServeFile(w, r, path)
}

// Wrap for an http function to recover its errors if possible and
// print a nice error page.
func errorHandler(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				log.Println("There was an error", err)
				w.WriteHeader(http.StatusInternalServerError)
				templates.ExecuteTemplate(w, "error.html", err)
			}
		}()
		fn(w, r)
	}
}

// Checks and aborts the execution if the passed error is not nil.
func check(err error) {
	if err != nil {
		panic(err)
	}
}
